package net.itxxw.search.service;

import net.itxxw.framework.domain.course.CoursePub;
import net.itxxw.framework.domain.course.TeachplanMediaPub;
import net.itxxw.framework.domain.search.CourseSearchParam;
import net.itxxw.framework.model.response.CommonCode;
import net.itxxw.framework.model.response.QueryResponseResult;
import net.itxxw.framework.model.response.QueryResult;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class EsCourseService {

    //先注入相关的配置参数，索引库名，索引库类型，索引显示字段
    @Value("${xuecheng.course.index}")
    private String index;
    @Value("${xuecheng.course.type}")
    private String type;
    @Value("${xuecheng.course.source_field}")
    private String source_field;
    //高可用的ES请求客户端
    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Value("${xuecheng.media.index}")
    private String media_index;
    @Value("${xuecheng.media.type}")
    private String media_type;
    @Value("${xuecheng.media.source_field}")
    private String media_field;

    /***
     * 课程索引搜索
     * @param page  当前页码
     * @param size  显示条数
     * @param courseSearchParam 综合查询条件，把所有查询条件，封装为一个条件查询的对象
     * @return  分页索引表的集合对象
     */
    public QueryResponseResult<CoursePub> list(int page, int size, CourseSearchParam courseSearchParam) {
        Logger LOGGER = LoggerFactory.getLogger(EsCourseService.class);
        //设置索引
        SearchRequest searchRequest = new SearchRequest(index);
        //设置类型
        searchRequest.types(type);
        //创建搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //创建布尔查询对象
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        //源字段过滤
        String[] fieldArr = source_field.split(",");
        searchSourceBuilder.fetchSource(fieldArr,new String[]{});

        //根据关键字进行查询
        if(StringUtils.isNotEmpty(courseSearchParam.getKeyword())){
            //匹配关键词
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "teachplan", "description");
            //设置匹配占比
            multiMatchQueryBuilder.minimumShouldMatch("70%");
            //提升字段的权重值
            multiMatchQueryBuilder.field("name",10);
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }

        //根据难度进行过滤
        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("mt",courseSearchParam.getMt()));
        }
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("st",courseSearchParam.getSt()));
        }
        //根据等级进行过滤
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
        }

        //设置分页参数
        if(page<=0){
            page = 1;
        }
        if(size<=0){
            size = 20;
        }
        //计算搜索起始位置
        int start = (page-1) * size;//课程的起始位置
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(size);

        //将布尔查询对象添加到搜索源内
        searchSourceBuilder.query(boolQueryBuilder);

        //配置高亮信息
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");
        highlightBuilder.postTags("</font>");
        //设置高亮字段
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        searchSourceBuilder.highlighter(highlightBuilder);

        //请求搜索
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try{
            searchResponse = restHighLevelClient.search(searchRequest);
        }catch (Exception e){
            //搜索异常
            e.printStackTrace();
            LOGGER.error("search error ...{}",e.getMessage());
            return new QueryResponseResult<>(CommonCode.FAIL,null);
        }

        //结果收集处理
        SearchHits hits = searchResponse.getHits();
        //获取匹配度高的结果
        SearchHit[] searchHits = hits.getHits();
        //总记录数
        long totalHits = hits.getTotalHits();
        //数据列表
        ArrayList<CoursePub> list = new ArrayList<>();

        //添加数据
        for (SearchHit hit: searchHits){
            CoursePub coursePub = new CoursePub();

            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //取出id
            String id = (String) sourceAsMap.get("id");
            coursePub.setId(id);
            //取出名称
            String name = (String) sourceAsMap.get("name");
            coursePub.setName(name);
            //图片
            String pic = (String) sourceAsMap.get("pic");
            coursePub.setPic(pic);

            try {
                if(sourceAsMap.get("price")!=null ){
                    Double  price = (Double) sourceAsMap.get("price");
                    coursePub.setPrice(price);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            //旧价格，价格不为空，才设置值，不然就保留null
            try {
                if(sourceAsMap.get("price_old")!=null ){
                    Double price_old = (Double) sourceAsMap.get("price_old");
                    coursePub.setPrice_old(price_old);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            list.add(coursePub);
        }

        //返回响应结果
        QueryResult<CoursePub> queryResult = new QueryResult<>();
        queryResult.setList(list);
        queryResult.setTotal(totalHits);
        return new QueryResponseResult<>(CommonCode.SUCCESS,queryResult);
    }


    /**
     * 根据id搜索课程发布信息
     * @param id 课程id
     * @return JSON数据
     */
    public Map<String, CoursePub> getdetail(String id) {
        //设置索引
        SearchRequest searchRequest = new SearchRequest(index);
        //设置类型
        searchRequest.types(type);
        //创建搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //设置查询条件,根据id进行查询
        searchSourceBuilder.query(QueryBuilders.termQuery("id",id));
        //这里不使用source的原字段过滤,查询所有字段
        // searchSourceBuilder.fetchSource(new String[]{"name", "grade", "charge","pic"}, newString[]{});
        //设置搜索源对象
        searchRequest.source(searchSourceBuilder);
       //执行搜索
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
       //获取搜索结果
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits(); //获取最优结果
        Map<String,CoursePub> map = new HashMap<>();
        for (SearchHit hit: searchHits) {
            //从搜索结果中取值并添加到coursePub对象
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//取原值，for循环只有1条记录
            String courseId = (String) sourceAsMap.get("id");
            String name = (String) sourceAsMap.get("name");
            String grade = (String) sourceAsMap.get("grade");
            String charge = (String) sourceAsMap.get("charge");
            String pic = (String) sourceAsMap.get("pic");
            String description = (String) sourceAsMap.get("description");
            String teachplan = (String) sourceAsMap.get("teachplan");
            CoursePub coursePub = new CoursePub();
            coursePub.setId(courseId);
            coursePub.setName(name);
            coursePub.setPic(pic);
            coursePub.setGrade(grade);
            coursePub.setTeachplan(teachplan);
            coursePub.setDescription(description);
            //设置map对象
            map.put(courseId,coursePub);
        }
        return map;
    }


    /**
     * 根据一个或者多个课程计划id查询媒资信息
     * @param teachplanIds 课程id
     * @return QueryResponseResult
     */
    public QueryResponseResult<TeachplanMediaPub> getmedia(String[] teachplanIds) {
        //设置索引
        SearchRequest searchRequest = new SearchRequest(media_index);

        //设置类型
        searchRequest.types(media_type);

        //创建搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //源字段过滤
        String[] media_index_arr = media_field.split(",");
        searchSourceBuilder.fetchSource(media_index_arr, new String[]{});

        //查询条件,根据课程计划id查询(可以传入多个课程计划id)
        searchSourceBuilder.query(QueryBuilders.termsQuery("teachplan_id", teachplanIds));

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取结果
        SearchHits hits = searchResponse.getHits();
        long totalHits = hits.getTotalHits();
        SearchHit[] searchHits = hits.getHits();

        //数据列表
        List<TeachplanMediaPub> teachplanMediaPubList = new ArrayList<>();

        for(SearchHit hit:searchHits){
            TeachplanMediaPub teachplanMediaPub =new TeachplanMediaPub();
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //取出课程计划媒资信息
            String courseid = (String) sourceAsMap.get("courseid");
            String media_id = (String) sourceAsMap.get("media_id");
            String media_url = (String) sourceAsMap.get("media_url");
            String teachplan_id = (String) sourceAsMap.get("teachplan_id");
            String media_fileoriginalname = (String) sourceAsMap.get("media_fileoriginalname");
            teachplanMediaPub.setCourseId(courseid);
            teachplanMediaPub.setMediaUrl(media_url);
            teachplanMediaPub.setMediaFileoriginalname(media_fileoriginalname);
            teachplanMediaPub.setMediaId(media_id);
            teachplanMediaPub.setTeachplanId(teachplan_id);
            //将对象加入到列表中
            teachplanMediaPubList.add(teachplanMediaPub);
        }

        //构建返回课程媒资信息对象
        QueryResult<TeachplanMediaPub> queryResult = new QueryResult<>();
        queryResult.setList(teachplanMediaPubList);
        queryResult.setTotal(totalHits);
        return new QueryResponseResult<TeachplanMediaPub>(CommonCode.SUCCESS,queryResult);
    }

}
